#ifndef MESHVIEW_HPP
#define MESHVIEW_HPP
#include "CreaseStructure.hpp"
#include "MeshDraw.hpp"
#include "PolyMesh.hpp"
#include "MeshViewConfig.hpp"
#include "MeshAdjacency.hpp"
#include "PolyMeshView.hpp"

// Top layer wrapping the mesh object.  
// Contains application-specific data and operations including:
// * View Configuration
// * Selected geometry
// * Subdivision mesh
// * Region list
// * Landmarks
// * much more...
class MeshView
{
public:
   enum Options
   {
      cKEEP_CREASE_STRUCTURE = 1
   };

   MeshView(bool aIsSubdivMesh = false);
   ~MeshView();

   void CreateSubdivisionMesh();
   MeshView* GetSubdivisionMesh() { return mSubdividedMesh; }
   void Draw();

   void UpdateMesh();

   std::string mName;
   PolyMesh    mMesh;
   const MeshViewConfig& GetConfig() { return mConfig; }
   void SetConfig(MeshViewConfig& aConfig,
                  bool            aSubdivConfig);
   const std::vector<int>& GetRegions() const { return mRegions; }
   void GetShownRegions(std::vector<int>& aRegions);
   bool        mVisible;
   
   void CopyConfigPart(MeshViewConfig& aLHS, const MeshViewConfig& aRHS)
   {
      aLHS.mFlipMaterials = aRHS.mFlipMaterials;
      aLHS.mHiddenRegions = aRHS.mHiddenRegions;
   }

   void SetSubdivision(int aLevel);
   int  GetSubdivision() { return mSubdivisionLevel; }

   template <typename AR>
   void serialize(AR& aAr, unsigned int aVersion)
   {
      aAr & mVisible & mName & mMesh & mConfig & mRegions & mSubdivisionLevel & mSubdividedMesh->mConfig;
   }
   
   void SelectAllVertices();
   std::vector<int>& GetSelectedVertices() { return mSelectedVerts; }
   void SelectionUpdated();
   CreaseStructure& GetCreases();

   void SetOptions(int aOptions) { mOptions |= aOptions; }
   void ClearOptions(int aOptions) { mOptions &= ~aOptions; }
   bool OptionSet(Options aOption) const { return 0 != (mOptions & aOption);}
   void MoveSelectedVerts(Vec3 offset);
   void RebuildBase();
   void Rebuild();
   void GetSelectedFaces(std::vector<int>& aFaces);
   void GetSelectedVerts(std::vector<int>& aVerts);
   void SetSelectedFaces(IndexList& aFaces);
   void ClearSelection();
   const IndexList& GetSelectedFaces() const { return mSelectedFaces; }
   MeshAdjacency& GetMeshAdjacency();
private:

   void DrawAllVerts();
   void UpdateSharedConfig(MeshViewConfig& aConfig);
   void DrawCentroid();
   void DrawSelVertices();
   void DrawSelLoops();
   void DrawSelFaces();
   void DrawSelEdges();

   void DrawFaces();

   void DrawLandmarks();

   void DrawWireframe(MeshDraw& aMeshDraw);

   void DrawEdges();

   void DrawPolys();

   void UpdateFaceMesh();

   void UpdatePolyMesh();

   void UpdateRegions();

   void RemoveHiddenMaterials(Mesh& aMesh);

   //! Copy of face mesh for rendering
   Mesh              mFaceMesh;
   MeshDraw          mFaceMeshDraw;

   PolyMeshView      mPolyView;
   MeshDraw          mPolyMeshDraw;

   MeshViewConfig    mConfig;
   

public:
   std::vector<int>  mSelectedVerts;
   std::vector<int>  mSelectedLoops;
   //int               mSelectedInterface;
   //std::vector<Vec3> mLandmarks;
   std::vector<MatPoint> mLandmarks;
   std::vector<Edge>     mSelectedEdges;

private:
   
   IndexList         mSelectedFaces;
   EdgeList          mSelectedFacesBorder;

   bool              mCreasesUpdated;
   CreaseStructure   mCreases;
   bool              mMeshAdjacencyValid;
   MeshAdjacency     mAdjacency;

   Vec3        mCentroid;
   std::vector<int>  mRegions;

   std::vector<int>  mShownVertices;

   bool        mPolyUpdating;
   bool        mFaceUpdating;

   int         mSubdivisionLevel;

   MeshView*   mSubdividedMesh;
   int         mOptions;
};
#endif